﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Reflection;

namespace DEScryp
{
    /// <summary>
    /// DES加密/解密类。
    /// </summary>
    public class DESEncryp
    {
        /// <summary>
        /// Des加解密
        /// </summary>
        /// <param name="key">密钥</param>
        /// <param name="data">数据</param>
        /// <param name="mode">模式，0为加密，1为解密</param>
        /// <param name="iv">向量</param>
        /// <returns></returns>
        /// 
        public static string Des(string key, string data, string mode, string iv = "", PaddingMode paddingMode = PaddingMode.None)
        {
            if (mode != "0" && mode != "00" && mode != "1" && mode != "01")
            {
                return "mode输入错误";
            }

            if (!(key.Length == 16 || key.Length == 32 || key.Length == 48))
            {
                return "key长度错误!";
            }

            if (data.Length % 16 != 0)
            {
                return "data长度错误!";
            }

            if (key.Length == 16)
            {
                return Des1(key, data, mode, iv, paddingMode);
            }
            else
            {
                return Des3(key, data, mode, iv, paddingMode);
            }

        }
        /// <summary>
        /// Des加解密
        /// </summary>
        /// <param name="key">密钥</param>
        /// <param name="data">数据</param>
        /// <param name="mode">模式，0为加密，1为解密</param>
        /// <param name="iv">向量</param>
        /// <returns></returns>
        public static byte [] Des(string key, byte[] data, string mode, string iv = "", PaddingMode paddingMode = PaddingMode.None)
        {

            if (mode != "0" && mode != "00" && mode != "1" && mode != "01")
            {
                return null;//"mode输入错误";
            }

            if (!(key.Length == 16 || key.Length == 32 || key.Length == 48))
            {
                return null;//"key长度错误!";
            }


            if (key.Length == 16)
            {
                return Des1(key, data, mode, iv, paddingMode);
            }
            else
            {
                return Des3(key, data, mode, iv, paddingMode);
            }
        }

        /// <summary>
        /// 3DES算法
        /// </summary>
        /// <param name="_key">密钥</param>
        /// <param name="_str">源数据</param>
        /// <param name="_mode">0加密，1解密</param>
        /// <param name="iv">向量，为空为ECB模式，不为空则为CBC模式</param>
        /// <returns>加解密后的数据</returns>
        public static byte [] Des3(string _key, byte[] _str, string _mode, string iv = "", PaddingMode mode= PaddingMode.None)
        {
            //byte[] str = hexStrToHexBuf(_str);
            byte[] key = hexStrToHexBuf(_key);
            if (_key.Length == 32)
            {
                key = hexStrToHexBuf(_key + _key.Substring(0, 16));
            }

            TripleDESCryptoServiceProvider des3 = new TripleDESCryptoServiceProvider();
            des3.Padding = mode;

            object _encrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Encrypt").GetValue(null);
            object _decrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Decrypt").GetValue(null);
            MethodInfo _newEncryptor = typeof(TripleDESCryptoServiceProvider).GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
            ICryptoTransform desCrypt3 = null;

            if (iv.Length == 0)
            {
                des3.Mode = CipherMode.ECB;

                if (_mode == "0" || _mode == "00")
                {
                    desCrypt3 = (ICryptoTransform)_newEncryptor.Invoke(des3,
                        new object[] { key, CipherMode.ECB, null, 0, _encrypt });
                }
                else
                {
                    desCrypt3 = (ICryptoTransform)_newEncryptor.Invoke(des3,
                        new object[] { key, CipherMode.ECB, null, 0, _decrypt });
                }
            }
            else
            {
                des3.IV = hexStrToHexBuf(iv);
                des3.Mode = CipherMode.CBC;

                if (_mode == "0" || _mode == "00")
                {
                    desCrypt3 = (ICryptoTransform)_newEncryptor.Invoke(des3,
                        new object[] { key, CipherMode.CBC, des3.IV, 0, _encrypt });
                }
                else
                {
                    desCrypt3 = (ICryptoTransform)_newEncryptor.Invoke(des3,
                        new object[] { key, CipherMode.CBC, des3.IV, 0, _decrypt });
                }

            }
            byte[] result3 = desCrypt3.TransformFinalBlock(_str, 0, _str.Length);
            return result3;
        }


        /// <summary>
        /// 3DES算法
        /// </summary>
        /// <param name="_key">密钥</param>
        /// <param name="_str">源数据</param>
        /// <param name="_mode">0加密，1解密</param>
        /// <param name="iv">向量，为空为ECB模式，不为空则为CBC模式</param>
        /// <returns>加解密后的数据</returns>
        public static string Des3(string _key, string _str, string _mode, string iv = "", PaddingMode mode = PaddingMode.None)
        {
            byte[] str = hexStrToHexBuf(_str);
            byte[] result3 = Des3(_key, str, _mode, iv, mode);
            return BitConverter.ToString(result3).Replace("-", "");

        }

        /// <summary>
        /// 单DES算法
        /// </summary>
        /// <param name="_key">密钥</param>
        /// <param name="_str">源数据</param>
        /// <param name="_mode">0加密，1解密</param>
        /// <param name="iv">向量，为空为ECB模式，不为空则为CBC模式</param>
        /// <returns>加解密后的数据</returns>
        public static byte[] Des1(string _key, byte[] _str, string _mode, string iv = "", PaddingMode mode = PaddingMode.None)
        {
            byte[] key = hexStrToHexBuf(_key);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            des.Padding = mode;

            object _encrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Encrypt").GetValue(null);
            object _decrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Decrypt").GetValue(null);
            MethodInfo _newEncryptor = typeof(DESCryptoServiceProvider).GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);

            ICryptoTransform desCrypt = null;

            if (iv.Length == 0)
            {
                des.Mode = CipherMode.ECB;

                if (_mode == "0" || _mode == "00")
                {
                    desCrypt = (ICryptoTransform)_newEncryptor.Invoke(des,
                        new object[] { key, CipherMode.ECB, null, 0, _encrypt });
                }
                else
                {
                    desCrypt = (ICryptoTransform)_newEncryptor.Invoke(des,
                        new object[] { key, CipherMode.ECB, null, 0, _decrypt });
                }
            }
            else
            {
                des.IV = hexStrToHexBuf(iv);
                des.Mode = CipherMode.CBC;

                if (_mode == "0" || _mode == "00")
                {
                    desCrypt = (ICryptoTransform)_newEncryptor.Invoke(des,
                        new object[] { key, CipherMode.CBC, des.IV, 0, _encrypt });

                }
                else
                {
                    desCrypt = (ICryptoTransform)_newEncryptor.Invoke(des,
                        new object[] { key, CipherMode.CBC, des.IV, 0, _decrypt });
                }

            }
            byte[] result3 = desCrypt.TransformFinalBlock(_str, 0, _str.Length);
            return result3;
        }
        /// <summary>
        /// 单DES算法
        /// </summary>
        /// <param name="_key">密钥</param>
        /// <param name="_str">源数据</param>
        /// <param name="_mode">0加密，1解密</param>
        /// <param name="iv">向量，为空为ECB模式，不为空则为CBC模式</param>
        /// <returns>加解密后的数据</returns>
        public static string Des1(string _key, string _str, string _mode, string iv = "", PaddingMode mode = PaddingMode.None)
        {
            byte[] str = hexStrToHexBuf(_str);
            byte[] result3 = Des1(_key, str, _mode, iv, mode);
            return BitConverter.ToString(result3).Replace("-", "");
        }
        /// <summary>
        /// 合并字符
        /// </summary>
        /// <param name="src"></param>
        /// <returns></returns>
        private static byte[] hexStrToHexBuf(string src)
        {
            int srclen = src.Length;
            if (srclen % 2 != 0)
            {
                return null;
            }
            int len = srclen / 2;
            int indexOfArray = -1;
            byte[] hexadecimalArray = new byte[len];
            for (int index = 0; index < len; index++)
            {
                string value = src.Substring(index * 2, 2);
                hexadecimalArray[++indexOfArray] = Convert.ToByte(value.ToUpper(), 16);
            }
            return hexadecimalArray;
        }

      


    }
}
